package com.hzeng.util;

import java.io.File;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.hyperic.sigar.CpuPerc;
import org.hyperic.sigar.Mem;
import org.hyperic.sigar.MultiProcCpu;
import org.hyperic.sigar.NetInterfaceConfig;
import org.hyperic.sigar.NetInterfaceStat;
import org.hyperic.sigar.ProcExe;
import org.hyperic.sigar.ProcMem;
import org.hyperic.sigar.ProcState;
import org.hyperic.sigar.ProcTime;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarProxy;
import org.hyperic.sigar.Swap;
import org.hyperic.sigar.cmd.Ps;
import org.hyperic.sigar.cmd.Shell;
import org.hyperic.sigar.cmd.SigarCommandBase;

public class ProgramMonitor extends SigarCommandBase{
	
	private static ProgramMonitor pm = new ProgramMonitor();
	private List<Long> pids = null;
	private static DecimalFormat df1 = new DecimalFormat("#0.00");
	
	private static final double DIVISOR = 1048576.0;
	
	public List<Long> getPids() {
		return pids;
	}

	public void setPids(List<Long> pids) {
		this.pids = pids;
	}

	public static ProgramMonitor getInstance() {
		if (pm == null) {
			pm = new ProgramMonitor();
		}
		return pm;
	}

	private ProgramMonitor(Shell shell) {
		super(shell);
	}

	private ProgramMonitor() {
		super();
	}
	
	public static double formatNumber(Object value) {
		
		return new Double(df1.format(value));
	}
	
	public static double formatNumber(Object value,String formatPattern) {
		DecimalFormat df2 = new DecimalFormat(formatPattern);
		return new Double(df2.format(value));
	}
	
	public static String formatNumberToString(Object value) {
		
		return df1.format(value);
	}
	
	public static String formatNumberToString(Object value,String formatPattern) {
		DecimalFormat df2 = new DecimalFormat(formatPattern);
		return df2.format(value);
	}
	
	public static void calculteOIRate(List<Program> firstProgram,List<Program> secondProgram) {
		for (int i = firstProgram.size() - 1; i >= 0; i--) {
			Program first = firstProgram.get(i);
			if (first.getPid() == 0) {
				for (int j = secondProgram.size() - 1; j >= 0; j--) {
					Program second = secondProgram.get(i);
					if (second.getPid() == first.getPid()) {
						// byte/1024 = KB
						// millsecond / 1000 = second
						//first.setWrite(formatNumber((second.getWriteBytes() - first.getWriteBytes()) * 1000 / (second.getTimestamp() - first.getTimestamp()) / 1024.0));
						//first.setRead(formatNumber((second.getReadBytes() - first.getReadBytes()) * 1000 / (second.getTimestamp() - first.getTimestamp()) / 1024.0));
						first.setWrite(formatNumber((second.getWriteBytes() - first.getWriteBytes()) / (second.getTimestamp() - first.getTimestamp()) * 1000 / 1024.0 / 8.0));
						first.setRead(formatNumber((second.getReadBytes() - first.getReadBytes()) / (second.getTimestamp() - first.getTimestamp()) * 1000 / 1024.0 / 8.0));
						break;
					}else {
						continue;
					}
				}
			}
		}
	}

	public void registerCommand(Map<String, Object> params) {
		// monitor --pids chrome --pids java -i 5s
		// ps "State.Name.eq=java"

		if (params != null && params.size() > 2) {
			if (params.containsKey("ps") && params.containsKey("interval")
					&& params.containsKey("program0")) {
				String[] args = new String[1];

				while (true) {
					for (Entry<String, Object> entry : params.entrySet()) {
						String key = entry.getKey();
						if (key.startsWith("program")) {
							args[0] = "State.Name.sw="
									+ entry.getValue().toString();
							try {
								output(args);
							} catch (SigarException e) {
								e.printStackTrace();
							}
						}
					}

					try {
						Thread.sleep(1000 * (Long) params.get("interval"));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

			}

		}

	}

	public void parseArgs(String[] args) {
		Map<String, Object> params = new HashMap<String, Object>();
		if (args != null) {
			if (args.length > 1) {
				if (args[0].equals("monitor")) {
					params.put("ps", true);
					int programCount = 0;
					for (int i = 1; i < args.length - 1; i++) {
						if (args[i] != null && args[i] != "") {
							if (args[i].toLowerCase().equals("--pids")
									&& args[i + 1] != null && args[i + 1] != "") {
								params.put("program" + programCount,
										args[i + 1]);
								programCount++;
							} else if (args[i].toLowerCase().equals("-i")
									&& args[i + 1] != null && args[i + 1] != "") {
								Long intervalTime = null;

								if (args[i + 1].endsWith("S")
										|| args[i + 1].endsWith("s")) {
									try {
										intervalTime = new Long(args[i + 1]
												.substring(0, args[i + 1]
														.length() - 1));
									} catch (Exception e) {
										System.out
												.println("param "
														+ args[i + 1]
														+ " is invalid,please use valid positive number instead.");
										break;
									}
								} else {
									try {
										intervalTime = new Long(args[i + 1]);
									} catch (Exception e) {
										System.out
												.println("param "
														+ args[i + 1]
														+ " is invalid,please use valid positive number instead.");
										break;
									}
								}
								if (intervalTime < 1) {
									intervalTime = 1l;
								}
								params.put("interval", intervalTime);
							}
						}
					}

					registerCommand(params);
				} else {
					System.out
							.println("parameter is invalid,please use 'monitor' instead.");
				}
			}
		} else {
			System.out.println("parameter is null.");
		}
	}
	
	public Program recordSystemInfo() {
		return recordSystemInfo(new Date().getTime());
	}
	
	public String[] recordOneSystemInfo(long timestamp) {
		String[] programRow = new String[8];
		programRow[0] = timestamp + "";
		
		//get IO read/write
		try {
			String[] ifNames = this.proxy.getNetInterfaceList();
			
			long firstTotalRead = 0l;
			long firstTotalWrite = 0l;
			
			for (int i = 0; i < ifNames.length; i++) {  
	            String name = ifNames[i];  
	            NetInterfaceConfig ifconfig = this.proxy.getNetInterfaceConfig(name);  
	           // System.out.println("IP address:   " + ifconfig.getAddress());
	            if ((ifconfig.getFlags() & 1L) <= 0L) {  
	                //System.out.println("!IFF_UP...skipping getNetInterfaceStat");  
	                continue;  
	            }  
                NetInterfaceStat statStart = this.proxy.getNetInterfaceStat(name);  
                firstTotalRead = firstTotalRead + statStart.getRxBytes();  
                firstTotalWrite = firstTotalWrite + statStart.getTxBytes();  
	        }  
			
             programRow[6] = firstTotalRead + "";
             programRow[7] = firstTotalWrite + "";
			
		} catch (SigarException e1) {
			programRow[6] = "0";
            programRow[7] = "0";
		}
		programRow[4] = "0";
        programRow[5] = "0";
        
		//get system CPU and Memeory usage
		CpuPerc cpuList[] = null;
		double cpuUsage = 0;
		try {
			cpuList = sigar.getCpuPercList();
		} catch (SigarException e) {
			e.printStackTrace();
		}
		
		for (int i = 0; i < cpuList.length; i++) {
			cpuUsage = cpuUsage + cpuList[i].getCombined();
		}
		
		cpuUsage = cpuUsage / 4.0;
		programRow[1] = formatNumberToString(cpuUsage * 100);
		
		String osName = System.getProperty("os.name");
		try {
			if (osName.toLowerCase().startsWith("windows")) {
		    	Swap swap = this.proxy.getSwap();
		    	
		    	programRow[2] = formatNumberToString(swap.getTotal()/DIVISOR);
		    	programRow[3] = formatNumberToString(swap.getUsed()/DIVISOR);
		    } else {
		    	Mem systemMem = this.proxy.getMem();
		    	programRow[2] = formatNumberToString(systemMem.getUsed()/DIVISOR);
		    	programRow[3] = formatNumberToString(systemMem.getTotal()/DIVISOR);
		    }
		} catch (SigarException e) {
			e.printStackTrace();
		}  
		  
		
		return programRow;
	}
	
	public Program recordSystemInfo(long timestamp) {
		Program sys = new Program();
		sys.setTimestamp(timestamp);
		sys.setName("system");
		sys.setPid(0l);
		
		//get IO read/write
		try {
			String[] ifNames = this.proxy.getNetInterfaceList();
			long TotalRead = 0l;  
            long TotalWrite = 0l;
			for (int i = 0; i < ifNames.length; i++) {  
	            String name = ifNames[i];  
	            NetInterfaceConfig ifconfig = this.proxy.getNetInterfaceConfig(name);  
	            
	            if ((ifconfig.getFlags() & 1L) <= 0L) {  
	              //  System.out.println("!IFF_UP...skipping getNetInterfaceStat");  
	                continue;  
	            }  
                NetInterfaceStat statStart = this.proxy.getNetInterfaceStat(name);  
                TotalRead = TotalRead + statStart.getRxBytes();  
                TotalWrite = TotalWrite + statStart.getTxBytes();  
                  
               // long read = (rxBytesEnd - rxBytesStart)*8/(end-start)*1000;  
	        }  
			sys.setReadBytes(TotalRead);
            sys.setWriteBytes(TotalWrite);
		} catch (SigarException e1) {
			sys.setReadBytes(0);
            sys.setWriteBytes(0);
		}  
		sys.setRead(0);
		sys.setWrite(0);
		
		//get system CPU and Memeory usage
		CpuPerc cpuList[] = null;
		double cpuUsage = 0;
		try {
			cpuList = sigar.getCpuPercList();
		} catch (SigarException e) {
			e.printStackTrace();
		}
		
		for (int i = 0; i < cpuList.length; i++) {
			cpuUsage = cpuUsage + cpuList[i].getCombined();
		}
		
		cpuUsage = cpuUsage / 4.0;
		sys.setCpu(formatNumber(cpuUsage * 100));
		
		String osName = System.getProperty("os.name");
		try {
			if (osName.toLowerCase().startsWith("windows")) {
		    	Swap swap = this.proxy.getSwap();
		        sys.setMemory(formatNumber(swap.getUsed()/DIVISOR));
		        sys.setTotalMemory(formatNumber(swap.getTotal()/DIVISOR));
		    } else {
		    	Mem systemMem = this.proxy.getMem();
				sys.setMemory(formatNumber(systemMem.getUsed()/DIVISOR));
		        sys.setTotalMemory(formatNumber(systemMem.getTotal()/DIVISOR));
		    }
		} catch (SigarException e) {
			e.printStackTrace();
		}  
		
		return sys;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void output(String[] args) throws SigarException {
		long[] pids;
		if (args.length == 0) {
			pids = this.proxy.getProcList();
		} else {
			pids = this.shell.findPids(args);
		}
		
		List info = new ArrayList();
		SigarProxy sigar = this.proxy;
		Date currentTime =  new Date();
		info.add(currentTime.getTime());
		
		
		DateTimeManagerUtil dateTimeManagerUtil = DateTimeManagerUtil.getInstance();
		info.add(dateTimeManagerUtil.format(currentTime, "yyyy-MM-dd"));
		info.add(dateTimeManagerUtil.format(currentTime, "HH:mm:ss"));
		
		//get system CPU and Memeory usage
		CpuPerc cpuList[] = null;
		
		try {
			cpuList = sigar.getCpuPercList();
			
		} catch (SigarException e) {
			e.printStackTrace();

		}
		
		double cpuUsage = 0;
		
		for (int i = 0; i < cpuList.length; i++) {
			cpuUsage = cpuUsage + cpuList[i].getCombined();
		}
		
		cpuUsage = cpuUsage / 4.0;
		
		String cpuUsageString = CpuPerc.format(cpuUsage);
		if(cpuUsageString != null && cpuUsageString.length() > 1) {
			cpuUsageString = cpuUsageString.substring(0,cpuUsageString.length() - 1);
		}
		
		info.add(cpuUsageString);
		
		Mem systemMem = sigar.getMem();
		System.out.println("Total = " + systemMem.getTotal() / 1024L / 1024L + "M av");
		System.out.println("Used = " + systemMem.getUsed() / 1024L / 1024L + "M used");
		System.out.println("Free = " + systemMem.getFree() / 1024L / 1024L + "M free");
		
		
		Swap swap = sigar.getSwap();  
        System.out.println("Total = " + swap.getTotal() / 1024L / 1024L + "M av");  
        System.out.println("Used = " + swap.getUsed() / 1024L / 1024L + "M used");  
        System.out.println("Free = " + swap.getFree() / 1024L / 1024L + "M free");
        
        info.add(swap.getUsed() / 1024L / 1024L);
        info.add(swap.getFree() / 1024L / 1024L);
        
        //start from here
        
        
        
        
		for (int i = 0; i < pids.length; i++) {
			long pid = pids[i];
			try {
				output(info,pid);
			} catch (SigarException e) {
				this.err.println("Exception getting process info for " + pid
						+ ": " + e.getMessage());
			}
		}

	}

	@SuppressWarnings("unchecked")
	public void output(List info, long pid) throws SigarException {
		/*
		 	# pid: 9540, name: firefox, bin: C:\Program Files\Mozilla Firefox\firefox.exe, cwd: C:\Program Files\Mozilla Firefox
			# pid: 4880, name: explorer, bin: C:\WINDOWS\Explorer.EXE, cwd: C:\Documents and Settings\hzeng
			#
			Timestamp, Date, Time, System CPU, System Memory Used (MB), System Memory Free (MB), 9540 CPU, 9540 VM (MB), 9540 Memory (MB), 4880 CPU, 4880 VM (MB), 4880 Memory (MB)
			1384250033380, 2013-11-12, 17:53:53, 3.15, 2721, 789, 0.00, 674, 169, 0.00, 253, 28
			1384250035948, 2013-11-12, 17:53:55, 4.41, 2723, 787, 0.20, 674, 169, 0.00, 253, 28
			1384250037966, 2013-11-12, 17:53:57, 3.90, 2724, 786, 0.00, 674, 169, 0.20, 253, 28
		 */

		println(join(getInfo(info, this.proxy, pid)));
	}

	@SuppressWarnings("unchecked")
	public static List getInfo(List info, SigarProxy sigar, long pid)
			throws SigarException {
		
		info.add(String.valueOf(pid));
		
		ProcState state = sigar.getProcState(pid);
		String unknown = "???";
		
		//chrome
		info.add(String.valueOf(state.getName()));

		try {
			// C:\Documents and Settings\hzeng\Local Settings\Application
			// Data\Google\Chrome\Application\chrome.exe

			ProcExe exe = sigar.getProcExe(pid);
			String name = exe.getName();
			info.add(name);
			info.add(exe.getCwd());
		} catch (SigarException e) {
			info.add(unknown);
		}

		//get process CPU usage and memory usage
		//MultiProcCpu cpu = this.proxy.getMultiProcCpu("Pid.Pid.eq=1116");
		MultiProcCpu cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + pid);
		System.out.println("Number of processes: " + cpu.getProcesses());
		System.out.println("Cpu usage: " + CpuPerc.format(cpu.getPercent()));
		System.out.println("Cpu time: "  + Ps.getCpuTime(cpu.getTotal()));

        ProcMem mem = sigar.getMultiProcMem("Pid.Pid.eq=" + pid);
        System.out.println("Size: " + Sigar.formatSize(mem.getSize()));
        System.out.println("Resident: " + Sigar.formatSize(mem.getResident()));
        System.out.println("Share: " + Sigar.formatSize(mem.getShare()));
        
        /*
        try {
        	ProcCpu cpu1 = sigar.getProcCpu(pid);
        	
        	info.add(CpuPerc.format(cpu1.getPercent()));
        	System.out.println("cpu=" + CpuPerc.format(cpu1.getPercent()));
        } catch (SigarException e) {}
        
		try {
			//{Resident=24289280, PageFaults=5588874, Size=383688704}
			ProcMem mem1 = sigar.getProcMem(pid);
			
			//VM
			info.add(Sigar.formatSize(mem1.getSize()));
			System.out.println("VM=" + Sigar.formatSize(mem1.getSize()));
			
			//Mem
			info.add(Sigar.formatSize(mem1.getResident()));
			System.out.println("MeM=" + Sigar.formatSize(mem1.getResident()));
		} catch (SigarException e) {
			info.add(unknown);
		}
		*/
		
		return info;
	}


	@SuppressWarnings("unchecked")
	public static String join(List info) {
		StringBuffer buf = new StringBuffer();
		Iterator i = info.iterator();
		boolean hasNext = i.hasNext();
		while (hasNext) {
			buf.append((String) i.next());
			hasNext = i.hasNext();
			if (hasNext)
				buf.append("\t");
		}

		return buf.toString();
	}

	public static String getCpuTime(long total) {
		long t = total / 1000;
		return t / 60 + ":" + t % 60;
	}

	public static String getCpuTime(ProcTime time) {
		return getCpuTime(time.getTotal());
	}

	@SuppressWarnings("unused")
	private static String getStartTime(long time) {
		if (time == 0) {
			return "00:00";
		}
		long timeNow = System.currentTimeMillis();
		String fmt = "MMMd";

		if ((timeNow - time) < ((60 * 60 * 24) * 1000)) {
			fmt = "HH:mm";
		}

		return new SimpleDateFormat(fmt).format(new Date(time));
	}
	
	public Program getProgramSchema(String pid) {
		if (pid == null) {
			return null;
		}else {
			try {
				long id = new Long(pid);
				return getProgramSchema(id);
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public String[] recordSysHeader() {
				
		String[] header = new String[8];
		header[0] = Constants._TIME;
		header[1] = Constants._SYS_NAME + " " + Constants._CPU;
		header[2] = Constants._SYS_NAME + " " + Constants._TOTAL_MEMORY;
		header[3] = Constants._SYS_NAME + " " + Constants._MEMORY;
		header[4] = Constants._SYS_NAME + " " + Constants._READ;
		header[5] = Constants._SYS_NAME + " " + Constants._WRITE;
		header[6] = Constants._SYS_NAME + " " + Constants._READBYTES;
		header[7] = Constants._SYS_NAME + " " + Constants._WRITEBYTES;
		return header;
	}
	
	public String[] recordProgramHeader(Program program) {
		if (program == null) {
			return null;
		}else {
			String[] header = new String[4];
			if (program.getPid() == 0) {
				return recordSysHeader();
			}else {
				header[0] = Constants._TIME;
				header[1] = program.getPid() + " " + Constants._CPU;
				header[2] = program.getPid() + " " + Constants._VM;
				header[3] = program.getPid() + " " + Constants._MEMORY;
			}
			return header;
		}
	}
	
	public List<String[]> recordAllProgramsHeader() {
		if (pids == null) {
			return null;
		}else {
			List<String[]> listHeaders = new ArrayList<String[]>();
			listHeaders.add(recordSysHeader());
				
			for (int i = 0; i < pids.size(); i++) {
				String[] header = new String[4];
				header[0] = Constants._TIME;
				header[1] = pids.get(i) + " " + Constants._CPU;
				header[2] = pids.get(i) + " " + Constants._VM;
				header[3] = pids.get(i) + " " + Constants._MEMORY;
				listHeaders.add(header);
			}
			return listHeaders;
		}
	}
	
	public String[] getAllProgramsHeader() {
		if (pids == null) {
			return null;
		}else {
			String[] header = new String[pids.size() * 3 + 1];
			
			try {
				header[0] = "Time";
				for (int i = 0; i < pids.size(); i++) {
					header[1 + i*3 + 0] = pids.get(i) + " " + Constants._CPU;
					header[1 + i*3 + 1] = pids.get(i) + " " + Constants._VM;
					header[1 + i*3 + 2] = pids.get(i) + " " + Constants._MEMORY;
				}
				return header;
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public List<String> recordAllProgramsName() {
		if (pids == null) {
			return null;
		}else {
			List<String> names = new ArrayList<String>();
			
			try {
				for (int i = 0; i < pids.size(); i++) {
					long id = pids.get(i);
					ProcExe exe;
					try {
						exe = this.proxy.getProcExe(id);
						String name = exe.getName();
						File file = new File(name);
						name = file.getName();
						names.add(name);
						
					} catch (SigarException e) {
						e.printStackTrace();
					}
				}
				return names;
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public String[] recordProgramsSchema(Program program) {
		if (program == null) {
			return null;
		}
		if (program.getPid() == 0) {
			return new String[]{Constants._SCHEMA_PREFIX + " " + Constants._PID + ": 0",Constants._NAME + ": " + Constants._SYS_NAME,Constants._BIN + ": " + Constants._SYS_NAME,Constants._CWD + ": root"};
		}
		String[] schema = new String[4];
		long id = program.getPid();
		ProcExe exe;
		try {
			exe = this.proxy.getProcExe(id);
			String name = exe.getName();
			
			schema[2] = Constants._BIN + ": " + name.replace("\\", "\\\\");
			File file = new File(name);
			name = file.getName();
			schema[0] = Constants._SCHEMA_PREFIX + " " + Constants._PID + ": " + id;
			schema[1] = Constants._NAME + ": " + name;
			
			
			schema[3] = Constants._CWD + ": " + exe.getCwd().replace("\\", "\\\\");
			
		} catch (SigarException e) {
			e.printStackTrace();
		}
		return schema;
	}
	
	public List<String[]> recordAllProgramsSchema() {
		if (pids == null) {
			return null;
		}else {
			List<String[]> schemas = new ArrayList<String[]>();
			schemas.add(new String[]{Constants._SCHEMA_PREFIX + " " + Constants._PID + ": 0",Constants._NAME + ": system",Constants._BIN + ": system",Constants._CWD + ": root"});
			try {
				for (int i = 0; i < pids.size(); i++) {
					String[] schema = new String[4];
					long id = pids.get(i);
					ProcExe exe;
					try {
						exe = this.proxy.getProcExe(id);
						String name = exe.getName();
						
						schema[2] = Constants._BIN + ": " + name.replace("\\", "\\\\");
						File file = new File(name);
						name = file.getName();
						schema[0] = Constants._SCHEMA_PREFIX + " " + Constants._PID + ": " + id;
						schema[1] = Constants._NAME + ": " + name;
						
						
						schema[3] = Constants._CWD + ": " + exe.getCwd().replace("\\", "\\\\");
						
					} catch (SigarException e) {
						e.printStackTrace();
					}
					schemas.add(schema);
				}
				return schemas;
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public String[][] getAllProgramsSchema() {
		if (pids == null) {
			return null;
		}else {
			
			String[][] schema = new String[4][pids.size()];
			schema[0][0] = Constants._SCHEMA_PREFIX + " " + Constants._PID + ": " + Constants._SYS_PID;
			schema[0][1] = Constants._NAME + ": " + Constants._SYS_NAME;
			schema[0][2] = Constants._BIN + ": " + Constants._SYS_BIN;
			schema[0][3] = Constants._CWD + ": " + Constants._SYS_CWD;
			try {
				for (int i = 0; i < pids.size(); i++) {
					long id = pids.get(i);
					ProcExe exe;
					try {
						exe = this.proxy.getProcExe(id);
						String name = exe.getName();
						schema[i + 1][2] = Constants._BIN + ": " + name.replace("\\", "\\\\");
						File file = new File(name);
						name = file.getName();
						schema[i + 1][0] = Constants._SCHEMA_PREFIX + " " + Constants._PID + ": " + id;
						schema[i + 1][1] = Constants._NAME + ": " + name;
						schema[i + 1][3] = Constants._CWD + ": " + exe.getCwd().replace("\\", "\\\\");
					} catch (SigarException e) {
						e.printStackTrace();
					}
					
				}
				return schema;
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public List<String[]> recordOneRowForAllPrograms() {
		if (pids == null) {
			return null;
		}else {
			List<String[]> listPrograms = new ArrayList<String[]>();
			
			
			long timestamp = new Date().getTime();
			
			listPrograms.add(recordOneSystemInfo(timestamp));
			for (int i = 0; i < pids.size(); i++) {
				long id = pids.get(i);
				String[] programRow = new String[4];
				programRow[0] = timestamp + "";
				
				
				ProcMem mem;
				MultiProcCpu cpu;
				try {
					cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + id);
					mem = this.proxy.getMultiProcMem("Pid.Pid.eq=" + id);
					
					programRow[1] = formatNumberToString(cpu.getPercent() * 100);
					programRow[2] = formatNumberToString(mem.getSize()/DIVISOR);
					programRow[3] = formatNumberToString(mem.getResident()/DIVISOR);
					
				} catch (SigarException e) {
					e.printStackTrace();
				}
				listPrograms.add(programRow);
			}
			return listPrograms;
		}
	}
	
	public List<Program> getOneDataForAllPrograms(long timestamp) {
		if (pids == null) {
			return null;
		}else {
			ArrayList<Program> oneData = new ArrayList<Program>();
			
			try {
				ProcMem mem = null;
				MultiProcCpu cpu = null;
				for (int i = 0; i < pids.size(); i++) {
					long id = pids.get(i);
					
					Program pro = new Program();
					pro.setPid(id);
					try {
						cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + id);
						mem = this.proxy.getMultiProcMem("Pid.Pid.eq=" + id);
						
						pro.setTimestamp(timestamp);
						pro.setCpu(formatNumber(cpu.getPercent() * 100));
						pro.setMemory(formatNumber(mem.getResident()/DIVISOR));
						pro.setVirtualMemory(formatNumber(mem.getSize()/DIVISOR));
						
					} catch (SigarException e) {
						e.printStackTrace();
					}
					oneData.add(pro);
				}
			} catch (Exception e) {
				return null;
			}
			return oneData;
		}
	}
	
	public List<Program> getOneDataForAllPrograms() {
		if (pids == null) {
			return null;
		}else {
			return getOneDataForAllPrograms(new Date().getTime());
		}
	}
	
	public String[] getOneRowForAllPrograms() {
		if (pids == null) {
			return null;
		}else {
			String[] row = new String[pids.size() * 3 + 1];
			
			try {
				row[0] = new Date().getTime() + "";
				for (int i = 0; i < pids.size(); i++) {
					long id = pids.get(i);
					
					ProcMem mem;
					MultiProcCpu cpu;
					try {
						cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + id);
						mem = this.proxy.getMultiProcMem("Pid.Pid.eq=" + id);
						
						row[1 + i*3 + 0] = formatNumberToString(cpu.getPercent() * 100);
						row[1 + i*3 + 1] = formatNumberToString(mem.getSize()/DIVISOR);
						row[1 + i*3 + 2] = formatNumberToString(mem.getResident()/DIVISOR);
						
					} catch (SigarException e) {
						e.printStackTrace();
					}
					
				}
				return row;
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public Program getProgramSchema(long pid) {
		Program p = new Program();
		p.setPid(pid);
		ProcExe exe;
		try {
			exe = this.proxy.getProcExe(pid);
			String name = exe.getName();
			p.setBin(name);
			File file = new File(name);
			name = file.getName();
			p.setName(name);
			p.setDirectoryName(exe.getCwd());
		} catch (SigarException e) {
			e.printStackTrace();
		}
		
		return p;
	}
	
	public Program getProgram(String pid) {
		if (pid == null) {
			return null;
		}else {
			try {
				long id = new Long(pid);
				return getProgram(id);
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	public Program getProgram(Long pid) {
		Program p = new Program();
		p.setPid(pid);
		ProcExe exe;
		try {
			exe = this.proxy.getProcExe(pid);
			String name = exe.getName();
			File file = new File(name);
			name = file.getName();
			p.setBin(name);
			p.setName(name);
			p.setDirectoryName(exe.getCwd());
			
			ProcMem mem = this.proxy.getMultiProcMem("Pid.Pid.eq=" + pid);
			p.setMemory(formatNumber(mem.getResident()/DIVISOR));
			p.setVirtualMemory(formatNumber(mem.getSize()/DIVISOR));
			
			MultiProcCpu cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + pid);
			p.setCpu(formatNumber(cpu.getPercent() * 100));
		} catch (SigarException e) {
			e.printStackTrace();
		}
		
		
		return p;
	}
	
	public Program getOneProgramData(String pid) {
		if (pid == null) {
			return null;
		}else {
			try {
				long id = new Long(pid);
				return getOneProgramData(id);
			} catch (Exception e) {
				return null;
			}
		}
	}
	
	
	public Program getOneProgramData(Long pid) {
		Program p = new Program();
		p.setPid(pid);
		p.setTimestamp(new Date().getTime());
		
		ProcMem mem;
		try {
			mem = this.proxy.getMultiProcMem("Pid.Pid.eq=" + pid);
			p.setMemory(formatNumber(mem.getResident()/DIVISOR));
			p.setVirtualMemory(formatNumber(mem.getSize()/DIVISOR));
			
		} catch (SigarException e) {
			e.printStackTrace();
		}
		
		MultiProcCpu cpu;
		try {
			cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + pid);
			p.setCpu(formatNumber(cpu.getPercent() * 100));
		} catch (SigarException e) {
			e.printStackTrace();
		}
		
		return p;
	}
	
	public List<Program> getAllProcessList() {
		long[] pids;
		List<Program> programs = new ArrayList<Program>();
		try {
			pids = this.proxy.getProcList();
			
			for(int i= 0;i<pids.length;i++) {
				long pid = pids[i];
				if (pid > 100) {
					Program p = new Program();
					p.setPid(pid);
					ProcExe exe = this.proxy.getProcExe(pid);
					String name = exe.getName();
					File file = new File(name);
					name = file.getName();
					p.setName(name);
					p.setDirectoryName(exe.getCwd());
					
					ProcMem mem = this.proxy.getMultiProcMem("Pid.Pid.eq=" + pid);
					p.setMemory(formatNumber(mem.getResident()/DIVISOR));
					p.setVirtualMemory(formatNumber(mem.getSize()/DIVISOR));
					
					MultiProcCpu cpu = sigar.getMultiProcCpu("Pid.Pid.eq=" + pid);
					p.setCpu(formatNumber(cpu.getPercent() * 100));
			        
					programs.add(p);
				}
				
			}
			
		} catch (SigarException e) {
			e.printStackTrace();
		}
		return programs;
	}

	public static void main(String[] args) throws Exception {
		// monitor --pids java --pids esms -i 5s
		ProgramMonitor pm = new ProgramMonitor();
		pm.parseArgs(args);
	}
	

}
